import copy
import re
import time

from qturboframe.lib.utils.by import By
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.public_ui.base_element import BaseElement

from BladeFerm.Lib.Common import logger
from BladeFerm.hui12_common.function import display_wait
from .page import Page
from .base_table import BaseTable
from .button import Button
from .input_type import InputType

class U_Table(BaseElement):
    '''
    运行管理 判定专写的组件其他类似情况需要注意兼容情况 ,由于情况特殊性，不继承HUItable，直接继承BaseElement
    '''
    def __init__(self, element_para, father=None, timeout=1, index=1):
        if isinstance(element_para, dict) and By.TEXT in list(element_para.keys())[0]:
            text = element_para.get(By.TEXT)
            xpath = ".//table//*[contains(normalize-space(text()),'{}')]//ancestor::div[contains(@class,'h-table-wrapper')][1]".format(text)
            elements = father.find_elements_by_attribute(By.XPATH, xpath, timeout=timeout)
            if len(elements)!=0:
                super().__init__(elements[index-1], father, timeout)
            else:
                raise SeleniumError("按照此路径'{}'没有找到对应的元素".format(xpath))
        else:
            key_list = [By.ID, By.NAME, By.CLASS_NAME, By.TAG_NAME, By.LINK_TEXT,
                        By.PARTIAL_LINK_TEXT, By.CSS_SELECTOR, By.XPATH]
            element_by = ''
            element_value = ''
            assist = ''
            for key, value in element_para.items():
                if key.lower() in key_list:
                    element_by = key
                    element_value = value
                else:
                    assist += '{}:{},'.format(key, value)
            temps = father.find_elements_by_attribute(element_by,element_value, assist=assist, timeout=timeout)
            logger.info("发现表数{}".format(len(temps)))

            #第index可见的表
            i=0
            find=False
            for temp in temps:
                if temp.is_displayed():
                    i+=1
                    if i == index:
                        find=True
                        logger.info("查找到第{}张表".format(i))
                        super().__init__(temp, father, timeout)
                        break
            else:
                if find == False:
                    raise SeleniumError("路径{}未找到第{}张table".format(element_para,index))
                else:
                    raise SeleniumError("按照此路径'{}'没有查找到可见的table".format(element_para))
        self.page()

    def page(self, idname=None, father=None):
        '''
        获取hui表格分页栏对象
        重写说明：操作员中心Page类的xpth定位和hui标准定位的xpth不同

        :Args:
         - idname: 分页栏的定位条件，字典类型：{'元素查找方式':'元素查找语句', '辅助属性':'辅助属性值'}
         - father: 分页栏的祖先级元素，可以给分页栏查找限定范围，这样就不需要在整个页面中查找

        :Example:
         - 例: table.page({'xpath':'./following-sibling::ul[@class="h-page"]'})
        '''
        if father is None:
            father = self.element
        if idname:
            self._page = Page(idname, father, 1)
        else:
            self._page = Page({By.CSS_SELECTOR: 'ul.h-page'}, father, 1)
        return self._page

    def _get_row_index(self, title_list, table_dict, turn_page=False):
        re_disabled = r'h-page-disabled'
        key_list = list(table_dict.keys())
        # 以输入数据作为索引查找表格行数
        rows = 0
        row_list = list()
        for i, key in enumerate(key_list):
            temp_list = list()
            text_list = list()

            # 获取指定列内容列表
            body_table = BaseTable(
                {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self._element, self.timeout)
            if len(text_list) == 0:
                try:
                    title_index = title_list.index(key)
                except:
                    continue
                else:
                    text_list = body_table.get_text_list(len(title_list), int(title_index + 1))
            if i == 0:
                rows = len(text_list)
                row_list = list(range(1, rows + 1))
            for j in row_list:
                if text_list[j - 1] == table_dict[key]:
                    temp_list.append(j)
            row_list = temp_list
            if len(row_list) == 0:
                break
        # 未找到数据行则进行表格翻页
        if len(row_list) > 0:
            return row_list[0]
        else:
            if turn_page:
                if self._page.exist():
                    if self._page.is_last():
                        return 0
                    else:
                        self._page.to_next()
                        return self._get_row_index( title_list, table_dict, turn_page)
                else:
                    return 0
            else:
                return 0
    def __get_row_indexes(self, title_list, table_dict, turn_page=False):
        key_list = list(table_dict.keys())
        # logger.debug('表格查找列名索引：' + str(key_list))
        # 以输入数据作为索引查找表格行数
        row_list = list()
        rows = 0
        for i, key in enumerate(key_list):
            text_list = list()
            temp_list = list()
            # 获取指定列内容列表
            if len(text_list) == 0:
                try:
                    title_index = title_list.index(key)
                    # logger.debug('第' + str(title_index + 1) + '列，名称：' + key)
                except:
                    # logger.debug('表格中没有列名：' + key)
                    pass
                else:
                    body_table = BaseTable(
                        {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self._element, self.timeout)
                    text_list = body_table.get_text_list(len(title_list), int(title_index + 1))
            if i == 0:
                rows = len(text_list)
                # logger.debug('当前页显示行数：' + str(rows))
                row_list = list(range(1, rows + 1))
            content_list = table_dict[key].split(',')
            for j in row_list:
                for k in content_list:
                    if text_list[j - 1] == k:
                        # logger.debug('要查找的内容：' + k)
                        # logger.debug('第' + str(j) + '行，内容：' + text_list[j - 1])
                        temp_list.append(j)
            row_list = temp_list
            if len(row_list) == 0:
                break
        # 判断是否找到数据行
        if len(row_list) > 0:
            return row_list
        else:
            # 翻页查找
            if turn_page:
                if self._page.exist():
                    if not self._page.is_last():
                        self._page.to_next()
                        # logger.debug("翻下一页查找。")
                        row_list.extend(self.__get_row_indexes(
                            title_list, table_dict, turn_page))
                    else:
                        return row_list
                else:
                    return []
            else:
                return []

    def check_cells_exist(self, table_dict, turn_page=False):
        '''
        检查单元格是否存在
        重新说明：增加了多列单项的表格校验（例：{'列1': 'xx', '列2': 'xx'}）

        :Args:
         - table_dict: 一组单元格列名和单元格内容，字典类型，例：{列名1:'内容1,内容2'}
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Example:
         - 例: table.check_cells_exist({'姓名':'admin, manager'}, True)
        '''
        # 表格数据检查
        key_list = list(table_dict.keys())
        for key in key_list:
            if table_dict.get(key) == '-':
                table_dict.pop(key)
        if not table_dict:
            raise AttributeError('表格检查条件为空！')
        if turn_page:
            if self._page.exist():
                self._page.to_first()

        # 获取列名列表
        head_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-header\']/table'}, self._element, self.timeout)
        title_list = head_table.get_title_list()
        #testUnit
        logger.debug('表格显示列名：' + str(title_list))
        # 查找单元格
        value_list = len(list(table_dict.values())[0].split(','))
        key_list = len(list(table_dict.keys()))

        if key_list > 1:
            row_list = self.__get_row_indexes( title_list, table_dict, turn_page)
            if len(set(row_list)) == value_list:
                logger.info('单元格存在，检查通过')
            else:
                raise SeleniumError('有单元格不存在，检查不通过，请检查数据后重试！')
        else:
            search_value_list = table_dict.get(list(table_dict.keys())[0]).split(',')
            for value in search_value_list:
                search_dict = {list(table_dict.keys())[0]:value}
                row = self._get_row_index( title_list, search_dict, turn_page)
                if row:
                    logger.info('列名为{}，内容为{}的单元格存在，检查通过！'.format(
                        list(table_dict.keys())[0], value))
                else:
                    raise SeleniumError('列名为{}，内容为{}的单元格不存在，检查不通过！'.format(
                        list(table_dict.keys())[0], value))

    def check_rows_reload_finish(self):
        '''
        判定表格行数是否加载完成
        :return:
        '''
        return display_wait(idname={By.CSS_SELECTOR: 'tr.u-table-row'}, flag=0, timeout=self.timeout, driver=self.element)

    def nocheckbox_select_rows(self, table_dict, title_name, turn_page=False):
        '''
        表格单元格点击选中(针对一些不带checkbox勾选的数据行)

        :Args:
         - table_dict: 一组单元格列名和单元格内容，字典类型，例：{列名1:'内容1,内容2'}
         - title_name: 表格所要勾选的列名
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Example:
         - 例: table.nocheckbox_select_rows({'姓名':'admin, manager'}, 列名,True)
        '''
        table_data = self.get_cell(table_dict, title_name)
        if table_data:
            # 进行表格勾选
            table_data.click()
            # hui点击触发时间有延迟
            time.sleep(0.5)

    def get_cell_by_row_index(self, title_name, row):
        '''
        根据列名和行数查找hui表格的单元格

        :Args:
         - title_name: 列名
         - row: 单元格所在的行数

        :Returns:
            返回查找的单元格

        :Example:
         - 例: table.get_cell_by_row_index('name', 2)
        '''
        if row == 0:
            raise SeleniumError('表格中没有第0行！')
        logger.info('开始表格单元格查询')
        # 获取列名列表
        head_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-header\']/table'}, self.element, self.timeout)
        title_list = head_table.get_title_list()
        logger.info(title_list)
        # 进行翻页判断，需要翻页则翻页
        if self._page.exist():
            # 获取表格每页显示行数
            rows = self._page.get_rows_in_page()
            if rows == 0:
                # 获取初始数据表格
                bodytable = BaseTable(
                    {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self.element, self.timeout)
                tr_list = bodytable.get_tr_list()
                rows = len(tr_list)
            # 行数若超过当前页面显示行数，则翻页
            if row <= 0:
                raise SeleniumError('表格行号出错！')
            else:
                if row % rows == 0:
                    pages = int(row / rows)
                    row = rows
                else:
                    pages = int(row / rows + 1)
                    row = row % rows
                self._page.to_page(pages)
        # 根据列名和行数查找单元格
        #支持模糊查询的方法
        table_cell = None
        for title in title_list:
            if title_name in title:
                table_cell = self.__get_cell(title_list, title, row)
                break
        else:
            logger.info('没有模糊查找到列名{}'.format(title_name))
        logger.info('单元格查询结束！')
        return table_cell

    def get_cell(self, table_dict:dict, title_name, turn_page=False):
        '''
        根据单元格列名和单元格内容查找hui表格中所在的单元格

        :Args:
         - table_dict: 列名和内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - title_name: 查找的单元格列名
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Returns:
            返回查找的单元格

        :Example:
         - 例: cell = table.get_cell({'姓名':'admin', '年龄':'25'}, '工号', True)
        '''
        # 表格数据检查
        key_list = list(table_dict.keys())
        for key in key_list:
            if table_dict.get(key) == '-':
                table_dict.pop(key)
        if not table_dict:
            logger.info('表格查询条件为空！')
            return None
        logger.info('开始表格行号查询')
        # 将表格翻至首页，然后进行逐页查找
        if self._page.exist():
            self._page.to_first()
        # 获取列名列表
        head_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-header\']/table'}, self._element, self.timeout)
        title_list = head_table.get_title_list()
        row = self._get_row_index( title_list, table_dict, turn_page)
        logger.info('表格行号查询结束！')
        if row == 0:
            raise SeleniumError('未根据查找条件找到表格行！')
        logger.info('开始表格单元格查询')
        #加入模糊匹配列名 对组合选第一个
        table_cell = None
        for title in title_list:
            if title_name in title:
                table_cell = self.__get_cell( title_list, title, row)
                break
        else:
            logger.error("列名不存在")
        logger.info('单元格查询结束！')
        return table_cell

    def select_rows(self, table_dict, turn_page=False):
        '''
        在当前页根据单元格列名和单元格内容勾选行

        :Args:
         - table_dict: 单元格列名和单元格内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Example:
         - 例: table.select_rows({'姓名':'admin, manager'})
        '''
        re_checked = 'h-checkbox-checked'
        # 表格数据检查
        key_list = list(table_dict.keys())
        for key in key_list:
            if table_dict.get(key) == '-':
                table_dict.pop(key)
        if not table_dict:
            logger.debug('表格查询条件为空，不勾选！')
            return
        elif table_dict.get('_all_'):
            logger.info('当前表格页全选！')
            self.select_all()
        else:
            logger.info('开始表格行号查询')
            # 将表格翻至首页，然后进行逐页查找
            if self._page.exist():
                self._page.to_first()
            # 获取列名列表
            head_table = BaseTable(
                {'xpath': './div/div/div[@class=\'u-table-header\']/table'}, self._element, self.timeout)
            title_list = head_table.get_title_list()
            row_list = self.__get_row_indexes(title_list, table_dict, turn_page)
            logger.info('表格行号查询结束！')
            if len(row_list) == 0:
                raise SeleniumError('未找到目标数据行！')
            logger.info('开始勾选表格行！')
            body_table = BaseTable(
                {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self._element, self.timeout)
            tr_list = body_table.get_tr_list()
            for row in row_list:
                td = tr_list[int(row - 1)].find_elements_by_attribute('tag name', 'td', timeout=self.timeout)[0]
                span = td.find_element_by_attribute(
                    'css selector', 'label.h-checkbox-wrapper>span.h-checkbox', timeout=self.timeout)
                if not re.search(re_checked, span.get_attribute('class')):
                    span.secure_click()
            logger.info('勾选表格行结束！')

    def select_row(self, table_dict, turn_page=False):
        '''
        在当前页根据单元格列名和单元格内容勾选行

        :Args:
         - table_dict: 单元格列名和单元格内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Example:
         - 例: table.select_row({'姓名':'admin','年龄':'25'}, True)
        '''
        re_checked = 'h-checkbox-checked'
        # 表格数据检查
        key_list = list(table_dict.keys())
        for key in key_list:
            if table_dict.get(key) == '-':
                table_dict.pop(key)
        if not table_dict:
            logger.info('表格查询条件为空！')
            return
        logger.info('开始表格行号查询')
        # 将表格翻至首页，然后进行逐页查找
        if self._page.exist():
            self._page.to_first()
        # 获取列名列表
        head_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-header\']/table'}, self._element, self.timeout)
        title_list = head_table.get_title_list()
        row = self._get_row_index( title_list, table_dict, turn_page)
        logger.info('表格行号查询结束！')
        if row == 0:
            raise SeleniumError('未找到目标数据行！')
        logger.info('开始勾选表格行！')
        body_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self._element, self.timeout)
        tr_list = body_table.get_tr_list()
        td = tr_list[int(row - 1)].find_elements_by_attribute('tag name', 'td', timeout=self.timeout)[0]
        span = td.find_element_by_attribute(
            'css selector', 'label.h-checkbox-wrapper>span.h-checkbox', timeout=self.timeout)
        if not re.search(re_checked, span.get_attribute('class')):
            span.secure_click()
        logger.info('勾选表格行结束！')

    def select_all(self):
        '''
        当前页表格行全选

        :Example:
         - 例: table.select_all()
        '''
        logger.info("当前表格页全选开始")
        re_checked = 'h-checkbox-checked'
        th = self._element.find_elements_by_attribute(
            'xpath', './div/div/div[@class=\'u-table-header\']/table/thead/tr/th', timeout=self.timeout)[0]
        span = th.find_element_by_attribute(
            'css selector', 'label.h-checkbox-wrapper>span.h-checkbox', timeout=self.timeout)
        if not re.search(re_checked, span.get_attribute('class')):
            try:
                span.secure_click()
            except Exception as e:
                self._driver.execute_script("arguments[0].click();", span)
        logger.info("当前表格页全选结束")

    def click_button_in_cell(self, table_dict: dict, title_name, button_text, turn_page=False):
        '''
        根据单元格列名和单元格内容查找hui表格中所在的单元格,并点击单元个的内容

        :Args:
         - table_dict: 列名和内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - title_name: 查找的单元格列名
         - button_text: 需要点击的按钮
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Returns:
            None

        :Example:
         - 例: cell = table.click_button_in_cell({'姓名':'admin', '年龄':'25'}, '工号', True)
        '''
        cell = self.get_cell(table_dict, title_name, turn_page)
        Button({By.TEXT:button_text}, cell).click()

    def __get_cell(self, title_list, title_name, row):
        table_cell = None
        fixed_cell_list = list()
        # 获取数据表格单元格列表
        body_table = BaseTable(
            {'xpath': './div/div/div[@class=\'u-table-body\']/table'}, self._element, self.timeout)
        cell_list = body_table.get_cell_list()

        temp_title_list, temp_cell_list = title_list,cell_list

        # 当前表格显示的行数
        rows = len(cell_list) / len(title_list)
        # logger.debug('当前页显示行数：{}/{}={}'.format(len(temp_cell_list), len(temp_title_list), rows))
        try:
            title_index = temp_title_list.index(title_name)
            # logger.debug('第' + str(title_index + 1) + '列，名称：' + title_name)
        except ValueError:
            raise SeleniumError('列名不存在！')
        else:
            cell_index = int(title_index + (len(temp_title_list) * (row - 1)))
            table_cell = temp_cell_list[cell_index]
        return table_cell

    def __join_list(self, tlist1, tlist2, list1, list2):
        templist2 = list()
        for i in range(0, int((len(list1) + len(list2)) / (len(tlist1) + len(tlist2)))):
            for j in range(0, len(tlist1)):
                templist2.append(list1[int(i * len(tlist1) + j)])
            for j in range(0, len(tlist2)):
                templist2.append(list2[int(i * len(tlist2) + j)])
        templist1 = copy.deepcopy(tlist1)
        templist1.extend(tlist2)
        return templist1, templist2

    def choice_radios_in_cell(self, table_dict: dict, title_name, data,
                              style="attribute", attribute_name="title", add=True, turn_page=False):
        '''
        根据单元格列名和单元格行数查找hui表格中所在的单元格,并进行单选框选择

        :Args:
         - table_dict: 列名和内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - title_name: 查找的单元格列名
         - data:选择的数据（如果有新增的功能则新增该数据，并选择）
         - style 查询单选框字体的方式  attribute 从属性中找名字 text拿起text
         -attribute_name 当style 为attribute时 指定属性名
          -add  如果单选框不满足条件是否采用点击增加按钮自拟输入
          -turn_page:是否翻页
        :Returns:
            None
        '''
        logger.info("进行单元格选框操作")
        cell = self.get_cell(table_dict, title_name, turn_page)
        radios = cell.find_elements_by_css_selector("label.h-radio-wrapper")
        if len(radios) == 0:
            logger.error("未找到单选框")
            return
        for radio in radios:
            if style=="attribute":
                radio_title=radio.get_attribute(attribute_name)
            elif style=="text":
                radio_title=radio.text
            else:
                logger.error("无效的查询方式")
                return
            if data in radio_title:
                span=radio.find_element_by_css_selector("span.h-radio")
                if "h-radio-checked" not in span.get_attribute("class"):
                    span.click()
                logger.info("点击单选框{}")
                break
        else:
            if add:
                logger.info("未找到匹配的单选框，开始选择自主创建数据")
                add_radio=radios[len(radios)-1]
                input_wrappers=add_radio.find_elements_by_css_selector("div.h-input-wrapper")
                if len(input_wrappers) ==0:
                    logger.info("没有输入框,查询增加按钮")
                    try:
                        add=cell.find_element_by_css_selector("i.icon-addition")
                        cell.click()
                        add.click()
                        logger.info("点击增加按钮")
                    except:
                        logger.error("增加按钮未找到，操作失败!!!!")
                        return
                    radios=cell.find_elements_by_css_selector("label.h-radio-wrapper")
                    add_radio=radios[len(radios)-1]
                    input_wrappers=add_radio.find_elements_by_css_selector("div.h-input-wrapper")
                input_type=InputType(input_wrappers[0])
                span=add_radio.find_element_by_css_selector("span.h-radio")
                if "h-radio-checked" not in span.get_attribute("class"):
                    span.click()
                logger.info("选择新数据")
                input_type.set_value(data)
                logger.info("成功填入数据")
            else:
                logger.error("选用选择框中没有的无效数据")

    def add_text_in_cell(self, table_dict: dict, title_name, text, turn_page=False):
        '''
        根据单元格列名和单元格行数查找hui表格中所在的单元格,并增添文本操作
        :Args:
         - table_dict: 列名和内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - title_name: 查找的单元格列名
         - text:选择的数据（如果有新增的功能则新增该数据，并选择）
         -turn_page:是否翻页
        :Returns:
            None
        '''
        logger.info("进行单元格选框操作")
        cell=self.get_cell(table_dict, title_name, turn_page)
        cell.click()
        input_wrappers=cell.find_elements_by_css_selector("div.h-input-wrapper")
        if len(input_wrappers)==0:
            logger.info("输入框未展开,寻找增加按钮")
            try:
                add=cell.find_element_by_css_selector("i.icon-addition")
                add.click()
                input_wrappers=cell.find_elements_by_css_selector("div.h-input-wrapper")
            except:
                logger.error("寻找失败，操作失败")
        inputtype=InputType(input_wrappers[0])
        inputtype.set_value(text)

    def del_text_in_cell(self, table_dict: dict, title_name, turn_page=False):
        '''
        根据单元格列名和单元格行数查找hui表格中所在的单元格,并增添文本操作
        :Args:
         - table_dict: 列名和内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - title_name: 查找的单元格列名
         -turn_page:是否翻页
        :Returns:
            None
        '''
        logger.info("进行单元格选框操作")
        cell=self.get_cell(table_dict, title_name, turn_page)
        cell.click()
        try:
            del_text=cell.find_element_by_css_selector("i.icon-delete")
            del_text.click()
        except:
            logger.error("未发现删除按钮")